package july.framework.exsolver.bean.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import july.framework.exsolver.bean.*;
import lombok.Data;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Data
public class MultiResolver implements Resolver {
    private String id;
    private String type; // 处理类型 目前有 line:行处理， multi：多行处理， 后续可以支持 block:块数据处理
    private String returnType;
    private List<String> sheets;

    private List<Location> locations;
    private Integer totalRows;

    private List<Prop> props;

    @Override
    public void init(JSONObject param) {

        this.id = param.get("id").toString();
        this.returnType = param.get("returnType").toString();
        this.type = param.get("type").toString();

        this.sheets = new ArrayList<>();
        this.sheets.addAll(JSON.parseArray(param.getString("sheets"), String.class));

        this.locations = new ArrayList<>();
        this.locations.addAll(JSON.parseArray(param.getString("locations"), Location.class));

        this.totalRows = param.getInteger("totalRows");

        this.props = new ArrayList<>();
        this.props.addAll(JSON.parseArray(param.getString("props"), Prop.class));


//        System.out.println(param);
//        System.out.println(JSON.toJSONString(this));
    }

    @Override
    public <T> List<T> getAnalizedData(Class<T> returnType, Map<String, List<ExRow>> sheetMap) throws
            IllegalAccessException, InstantiationException {

        List<T> res = new ArrayList<>();

        if (this.sheets == null){
            return null;
        }

        for (int i = 0; i < this.sheets.size(); i++) {
            List<ExRow> rows = sheetMap.get(this.sheets.get(i));
            if (rows == null){
                return null;
            }

            for (int j = 0; j < rows.size(); j++) {
                ExRow row = rows.get(j);
                if (checkLocation(row, rows, j)){
                    T obj = createObj(returnType, rows, j);
                    if (obj == null){
                        continue;
                    }

                    res.add(obj);
                    j += this.totalRows;
                }
            }
        }

        return res;
    }

    /**
     * 数据定位成功后，根据属性获取数据值
     * @param returnType
     * @param allRows
     * @param curIndex
     * @param <T>
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private <T> T createObj(Class<T> returnType, List<ExRow> allRows, int curIndex) throws IllegalAccessException, InstantiationException {
        Object obj = returnType.newInstance();

        for (int i = 0; i < this.props.size(); i++) {
            Prop prop = this.props.get(i);
            Integer rowIndex = prop.getRow() == null ? prop.getAbsoluteRow() : prop.getRow();
            Integer colIndex = prop.getColumn() == null ? prop.getAbsoluteColumn() : prop.getColumn();
            String propName = prop.getPropName();

            // 如果配置了校验，进行校验
            List<Check> checks = prop.getChecks();
            if (checks != null){
                for(Check check : checks){
                    if (!doCheck(allRows,curIndex)){
                        return null;
                    }
                }
            }

            // 获取属性值
            ExRow checkRow = allRows.get(curIndex + rowIndex);
            ExCell checkCell = checkRow.getCells().get(colIndex);
            String value = checkCell.getValue();

            // 填入属性，调用setter方法
            String methodName = "set" + propName.substring(0,1).toUpperCase() + propName.substring(1);
            try {

                for (Method method : returnType.getMethods()){
                    String mName = method.getName();

                    if (mName.equals(methodName)){
                        //Class[] clzs = method.getParameterTypes();
                        method.invoke(obj, value);
                    }
                }

            } catch (InvocationTargetException e) {
                e.printStackTrace();
                continue;
            }

        }


        return (T)obj;
    }

    /**
     * 校验
     * @param allRows
     * @param curIndex
     * @return
     */
    private boolean doCheck(List<ExRow> allRows, int curIndex){
        return true;
    }

    /**
     * 数据定位
     * @param currentRow
     * @param allRows
     * @param curIndex
     * @return
     */
    private boolean checkLocation(ExRow currentRow, List<ExRow> allRows, int curIndex){
        if (this.locations == null){
            return false;
        }

        for (int i = 0; i < this.locations.size(); i++) {
            Location location = this.locations.get(i);

            Integer rowIndex = location.getRow() == null ? location.getAbsoluteRow() : location.getRow();
            Integer colIndex = location.getColumn() == null ? location.getAbsoluteColumn() : location.getColumn();
            String value = location.getValue();

            if (curIndex + rowIndex >= allRows.size()){
                return false;
            }

            ExRow checkRow = allRows.get(curIndex + rowIndex);

            if (colIndex >= checkRow.getCells().size()){
                return false;
            }
            ExCell checkCell = checkRow.getCells().get(colIndex);

            if (!value.equals(checkCell.getValue())){
                return false;
            }
        }

        return true;
    }
}
